Ruby Gems Cheat Sheet


GEM 설정

gem environment
set GEM_PATH = D:\dev\ruby192\lib\ruby\gems\1.9.1\gems
gem update --system
gem uninstall gemname
bundle update
(vendor 폴더에 bundle 설치하기)
bundle install --path vendor/bundle


devise

Controller filters and helpers

Devise will create some helpers to use inside your controllers and views. To set up a controller with user authentication, just add this before_filter:
before_filter :authenticate_user!
To verify if a user is signed in, use the following helper:
user_signed_in?
For the current signed-in user, this helper is available:
current_user
You can access the session for this scope:
user_session
Callbacks
    after_set_user
    after_authentication
    before_failure
    before_logout
    Warden::Manager.after_authentication do |user,auth,opts|
        user.last_login = Time.now
    end
   

generator

devise g view with haml
rails g devise_views -t=haml

OmniAuth

Add :password => Devise.friendly_token[0,20] when creating a new user from facebook omniauth.

Passwords Encrypt manually


Assuming you have a mysql database with a "users" table and a "password" column And an ActiveRecord model class called "user" that is hooked up to devise
Create an ActiveRecord model class in your app app/models/old_user.rb
OldUser < ActiveRecord::Base
  set_table :users
  establish_connection :database => "old_database", :user => "old user", :adapter => "mysql"
end
then create a rake task: app/lib/tasks/migrate_users.rake
task :migrate_users => :environment do
  OldUser.find_each do |old_user|
    u = User.new(:email => old_user.email, :password => old_user.password, :password_confirmation => old_user.password);
    #if your using confirmation
    u.skip_confirmation!
    u.save!
  end
end
Modify as necessary (make sure you're saving any app-specific user attributes)
Then$ rake migrate_users
   
Good news and bad news.
Good news:
The following works to create your user's password manually.
 pepper = nil
 cost = 10
 encrypted_password = ::BCrypt::Password.create("#{password}#{pepper}", :cost => cost).to_s
You can find your pepper and cost in your devise initializer. This method was confirmed using Devise's "valid_password?" method.
Bad news:
The entire reason I was trying to avoid "User.new(password: password).encrypted_password" was because of speed. It's terribly slow. With all my other pieces of my import task, I've intentionally avoided this.
But as it turns out, the major cost here is not instantiating a User object -- but BCrypt itself. There is very little noticeable speed boost when using BCrypt directly because it's intentionally designed to be slow.
My final answer: suck it up, run the rake script, go find a beverage.

mailer locale configuration

-ActionMailer::Base.default_url_options[:locale] = I18n.locale


Simple_form

<%= simple_form_for(@user, :builder => CustomBuilder) do |f| %>
  <%= f.input :name %>
<% end %>


Client side validations

Client side validations Registering own form builder
https://github.com/bcardarella/client_side_validations/wiki/Registering-your-own-custom-form-builder


Client MVC

Spine

Important is only that the public directory of the application is specified
as domainroot in Confixx. If the domain is called Passenger will start automatically.."
rails g spine:model Card text is_private order user_id card_type
rails g spine:controller Cards
rails g spine:scaffold card text is_private order user_id card_type
rails g spine:model Organization title description url image admins members followers
rails g spine:controller Organizations
rails g spine:scaffold organization title description url image admins members followers
var card = App.Card.create({ 
  is_private: true,
  order: 0,
  card_type: 'Reason',
  text: 'Spine & Rails, sitting in a tree!'
});
straightforward way to do that without extending Spine Model's
to allow for instances to be added in memory without syncing
Ajax.disable -> saveStuff()
Model.refresh()
extends
Contact.extend(Spine.Model.Ajax);
Contact.extend({
url: '/users/'
});
'/': ->
    if AuthenticatedUser
         @controller = new OtherController
         @replace @controller.render()
    else
         @controller = new LoginController
         @replace @controller.render()
http://spinejs.com/docs/controller_patterns         
         


Compass

compass init rails D:/dev/workspace/baksisi
compass init rails -r html5-boilerplate -u html5-boilerplate --syntax sass --force
css와 javascript를 asset 폴더로 옮겨준다. rails.js는 제외 (jquery_ujs와 동일하다)


Geo_location

https://github.com/chrisyour/geo_location
http://www.maxmind.com/app/geolitecountry


Mongoid id 변경하기

http://blog.joshdzielak.com/blog/2011/12/24/tame-the-mongoid-id-field-in-your-rails-and-backbone-js-app/
http://lostechies.com/derickbailey/2011/06/17/making-mongoid-play-nice-with-backbone-js/


Mongoid Follow unfollow

class User
  include Mongoid::Document
  field :name, type: String
  has_and_belongs_to_many :following, class_name: 'User', inverse_of: :followers, autosave: true
  has_and_belongs_to_many :followers, class_name: 'User', inverse_of: :following
  def follow!(user)
    if self.id != user.id && !self.following.include?(user)
      self.following << user
    end
  end
  def unfollow!(user)
    !self.following.include?(user)
    self.following.delete(user)
  end    
end
relation_ids instead? that is self.member_count = self.member_ids.size
self.challenged.where(_id: event.id).destroy_all
def unchallenge!(announce)
  self.announcements.destroy_all( conditions: { _id: announce.id })
  self.save!
end
Finally I successfully deleted the relation using self.challenged_ids.delete(event.id)
validates_inclusion_of :foo, in: [['foo'], ['bar']]


Mongoid polymorphic behaviour

When a child embedded document can belong to more than one type of parent document, you can tell Mongoid to support this by adding the as option to the definition on the parents, and the polymorphic option on the child.
class Doctor
  include Mongoid::Document
  embeds_one :name, as: :namable
end
class Nurse
  include Mongoid::Document
  embeds_one :name, as: :namable
end
class Name
  include Mongoid::Document
  embedded_in :namable, polymorphic: true
end


TEST

Cucumber

rails g cucumber:install ?capybara ?rspec
  ruby script/rails generate cucumber:feature user email:string password:string confirm_password:string name:string nickname:string gender:integer location_name:string location:integer email_is_priavate:boolean name_is_private:boolean danted:boolean description:string
  ruby script/rails generate scaffold post title:string body:text published:boolean
  rake db:migrate
  rake cucumber


Cucumber Errors Handling

If SystemStackError: stack level too deep 
Then add gem "rspec", ">= 2.6.0.rc2", :group => [:development, :test] to Gemfile


Cucumber & Capybara Ajax

sleep second
page.driver.browser.execute_script %Q{ $('.ui-menu-item a:contains("#{link_text}")').trigger("mouseenter").click(); }
Clicking any element with Cucumber and Capybara
class Capybara::XPath
  class << self
    def element(locator)
      append("//*[normalize-space(text())=#{s(locator)}]")
    end
  end
end
When 'I click "$locator"' do |locator|
  msg = "No element found with the content of '#{locator}'"
  locate(:xpath, Capybara::XPath.element(locator), msg).click
end
The step looks for any element with the given text. Here it is in use:
Scenario: Creating an item
  Given I am signed in as "brandon@example.com"
   When I click "Add to your list"
    And I fill in "Description" with "blog about clicking any element"
    And I press enter
   Then I should see "The item was added to your list"
    And I should see "blog about clicking any element"
   


Cucumber Capybara

selenium chrome driver
https://github.com/jnicklas/capybara
http://code.google.com/p/chromium/downloads/list
http://code.google.com/p/selenium/wiki/ChromeDriver#Overriding_the_Chrome_binary_location
Capybara.register_driver :selenium_with_firebug do |app|
  Capybara::Driver::Selenium
  profile = Selenium::WebDriver::Firefox::Profile.new
  profile.add_extension(File.expand_path("features/support/firebug-1.6.0-fx.xpi"))
  Capybara::Driver::Selenium.new(app, { :browser => :firefox, :profile => profile })
end
Before("@selenium_with_firebug") do
  Capybara.current_driver = :selenium_with_firebug
end


I18n

I18n-js initialize

layout/application.html.haml
- html_tag :class => 'no-js', :lang => "#{I18n.locale}"
applcation.js
I18n.default_locale = "en"
I18n.locale = $($("html")[0]).prop("lang")
I18n.fallbacks = true


Media - Flickraw

    flickr.upload_photo(params[:photo].tempfile.path)


Gem Trouble shooting

Q. `require': no such file to load -- thin (LoadError)
A. => Add gem 'thin' to Gemfile


Rails Performance

  • Curb for Http (libcurl)
  • Yajl, the fastest JSON library.
  • excon #=> faster http
  • Nokogiri, the fastest XML library.
  • Snappy, super fast compression tool by google.
  • fast_xs
  • Memcache. (libmemcached)
  • use Ree Garbage Collector

Fastest Server

  • Unicorn
  • Thin

Profiling Tools


Rack-bug

1. Install rack-bug (branch rails3) as plugin
cd vendor/plugins
git clone -b rails3 https://github.com/brynary/rack-bug.git
If you want to you it as gem then add following line into Gemfile
gem 'rack-bug', :git => 'https://github.com/brynary/rack-bug.git', :branch => 'rails3'
2. Replace the code from file actionview_extension.rb
which is avilable in vendor/plugins/rack-bug/lib/rack/bug/panels/templates_panel/ as specified in bug of rack_bug repository
if defined?(ActionView) && defined?(ActionView::Template)
ActionView::Template.class_eval do
def render_with_rack_bug(*args, &block)
Rack::Bug::TemplatesPanel.record(virtual_path) do
render_without_rack_bug(*args, &block)
end
end
alias_method_chain :render, :rack_bug
end
end
If you are using gem override the specified file in some way
3. Add following lines into your config.ru
require 'rack/bug'
use Rack::Bug, :secret_key => "someverylongandveryhardtoguesspreferablyrandomstring"
run myapp
4. Start your server and access the URL http://your_app/__rack_bug__/bookmarklet.html
and enter the password.
http://blog.railsupgrade.com/2011/04/configure-rack-bug-for-rails-3.html


출처